Компиляторы и интерпретаторы. Си, Фортран, Паскаль и Бейсик — примеры популярных языков высокого уровня. При составлении программы вы можете использовать алгебраические выражения вроде
χ = (—Ь + sqrt (b*b — 4*а*с))/(2*а)
и управляющие структуры типа if…elseif… else, for…, while… и do…. Вам не приходится гонять туда и обратно крошечные порции информации объемом 1 байт или заботиться об адресации, сохранении регистров и прочем; вы просто объявляете переменные и массивы с указанием типов и размеров, а затем используете их в арифметических и логических выражениях. Не жизнь, а малина.
Выше шла речь об исходном тексте, который можно преобразовать в выполнимую программу двумя способами. Исходные программы на языках Си или Фортран компилируются, т. е. преобразуются специальной программой (компилятором языка) в строки на языке ассемблера; затем программа ассемблера переводит этот промежуточный язык ассемблера в машинный язык[7]. Программы же на языках Бейсик и АПЛ обычно интерпретируются; вместо преобразования исходной программы в программу на языке ассемблера интерпретатор анализирует предложения программы и выполняет соответствующие машинные команды.
В целом интерпретация занимает гораздо больше времени, чем компиляция. Поскольку, однако, в случае интерпретации отсутствуют процессы компиляции, ассемблирования или компоновки (о компоновке см. ниже), программу можно запустить немедленно после ее ввода в машину. Интерпретирующие программы часто включают простые редакторы, удобные для быстрой модификации программы перед ее повторным пуском в процессе отладки. На заре микрокомпьютерной техники, когда жесткие диски были редкостью, интерпретатор Бейсик приобрел широкую популярность, поскольку он работает целиком в памяти; этому можно противопоставить утомительный многоступенчатый процесс компиляции. Однако сегодня быстрые диски и эффективные компиляторы снимают с нас все заботы. Любопытно отметить, что современные компиляторы часто следуют примеру интерпретирующей системы Turbo Pascal фирмы Borland и предоставляют вам «среду программирования», в которой можно без всяких усилий переходить от редактора к выполняемой программе. Если программа натыкается на ошибку, система возвращает вас в редактор и отмечает при этом неправильное предложение; такого рода системы включают отладчики, библиотекари и другие полезные и приятные средства.
Очевидным любимцем серьезных программистов является язык Си, сочетающий в себе мощность языка высокого уровня с красотой структурированных языков и гибкостью программ на языке ассемблера, обеспечивающих доступ к отдельным битам. Однако в научных приложениях львиная доля программирования все еще выполняется на языке Фортран.
Компоновщики и библиотеки. Ассемблер образует программу на машинном языке (собственно говоря, не совсем; ее часто называют «настраиваемым» или «перемещаемым»[8] модулем) из программы на языке ассемблера, образованной компилятором, или из отдельных подпрограмм, непосредственно написанных на этом языке. Кроме этого, обычно имеются программы, используемые отдельными командами языка высокого уровня. Так, в программе на языке Си может потребоваться обратиться к математической функции вроде sqrt (вычисление квадратного корня), или к сонму функций ввода-вывода, таких как printf или fopen. Весь бюрократический кошмар получения из «библиотеки» необходимых подпрограмм (в объектной форме), а затем настройки переходов и адресаций в программе, чтобы вся эта каша разместилась в памяти должным образом, берет на себя программа, называемая компоновщиком[9]).
В функции компоновщика входит назначение конкретных числовых значений ссылкам на ячейки памяти и адресам переменных в ассемблированной программе, и сделать это компоновщик может, только выяснив, какая программа вызывает какую и сколько места занимает каждая программа в памяти. Именно поэтому программа на машинном языке, получаемая с выхода ассемблера, должна быть настраиваемой, так же, как и ассемблированные подпрограммы, хранящиеся в различных библиотеках [обычно их несколько — библиотека встроенных функций компилятора, библиотека ввода-вывода, математическая библиотека, библиотека системных вызовов и, возможно, созданная дома (или купленная в магазине) библиотека полезных подпрограмм].
Редакторы и форматирующие программы. В доисторическую эпоху (до 1970 г.) вы могли наткнуться на программиста, несущего колоду перфокарт. Действительно, вы писали программу от руки на бланках программирования, затем пробивали, ее (или платили кому-то за пробивку) на «картах IBM» — аккуратных прямоугольниках из тонкого картона пастельных оттенков. В наши дни даже первоклашки умеют работать с текстовыми редакторами, обеспечивающими универсальный метод ввода программ в машину. Ветераны (те, кому за 30) помнят еще первые неуклюжие «интерактивные» редакторы, с помощью которых можно было создать и модифицировать текстовый файл; от этого файла по причинам, ведомым лишь самому редактору, вы всегда могли наблюдать лишь кусочек. Дан Ланкастер искушал нас своей «телевизионной пишущей машинкой», которая позволяла вывести на телевизор строку текста. И больше ничего. Ни редактирования, ни памяти, ни ничего. Поэтому легко поверить, что наш восторг не имел границ, когда мы впервые познакомились с «полноэкранным» редактором.
Хороший редактор (а сейчас они все хорошие) позволяет вам вводить и корректировать текст по мере его ввода, искать требуемые слова, изменять текст, перемещать блоки текста, открывать несколько окон для работы с несколькими файлами и создавать «макроопределения» для выполнения сложных манипуляций. Экран быстро отражает вносимые в текст изменения, даже если вы добавляете строки в начале большого файла. Даже очень большой размер файлов не замедляет процесса редактирования.
Универсальный редактор не знает, да и не интересуется тем, что вы пишите; это может быть программа, или сонет, или книга. Редактор просто создает текстовый файл в соответствии с вашими инструкциями, вводимыми с клавиатуры. Если файл состоит из предложений языка программирования, компилятор, интерпретатор или ассемблер читает его непосредственно. Если, с другой стороны, файл представляет собой текст, который вы хотите напечатать, у вас есть две возможности: прямо послать файл на принтер или дополнить его информацией о форматировании и передать форматирующей программе, которая скажет принтеру, как именно следует печатать текст. Хорошая программа форматирования заботится о полях, выравнивании строк, выделении разного места под буквы разной ширины, смене шрифтов, курсиве, жирном тексте, подчеркивании и т. д. Часто редактор и программа форматирования объединяются, причем иногда вы можете посмотреть на экране, как в действительности будет выглядеть напечатанная страница текста [это средство называется WYSIWYG (произносится «визивиг»), What You See Is What You Get-что вы видите, то вы и имеете]; однако чаще экран лишь частично отображает окончательный вид печатной страницы. Наиболее совершенные редакторы могут вставлять в текст математические и научные формулы. Для получения оригинал-макета вы вводите текст с клавиатуры наборной машины, которая сама выполняет экспонирование фотобумаги или фотопленки; лазерные или электролюминесцентные принтеры обеспечивают весьма приличное качество печати при умеренной цене и высокой скорости; ударные матричные принтеры относятся к самым дешевым, и результат оказывается соответствующим.
Редакторы, выполняющие форматирование, имеют характерные имена, например, MacWrite, Manuscript, Microsoft Word, Sprint, WordPerfect.
К популярным программам форматирования (которые могут работать и с текстом и с формулами) относятся ТЕХ и Troff. Одно предупреждение: в процессе создания текста (в противоположность программам) большинство редакторов с форматированием включают в поток редактируемого текста необычные символы, с помощью которых отмечается, например, курсив или временный конец строки. Эти символы не принимаются компиляторами или ассемблерами. Если вы не хотите, чтобы компилятор подавился вашей программой, вы должны создать текст без всяких упражнений, для чего запустить редактор в самом простом режиме «чистого» текста.
Вот еще пара бесплатных советов: а) найдите хороший редактор и держитесь его; б) не пытайтесь убедить коллег, что ваш редактор лучше какого-нибудь другого.
10.18. Операционные системы, файлы и использование памяти
Операционные системы. Из предыдущих обсуждений можно сделать вывод, что пользователю микрокомпьютера приходится часто запускать разнообразные программы, которые, к тому же, должны обмениваться между собой данными. Если, например, вам надо написать программу, то вы начинаете с запуска текстового редактора и создаете с его помощью текстовый файл, вводя строки программы с клавиатуры (хорошие программисты, насколько мы можем об этом судить, никогда не берут в руки карандаш). Сохранив на время этот файл, вы вызываете программу компилятора и компилируете сохраненный текстовый файл, чтобы получить файл с программой на языке ассемблера. Этот файл вы тоже сохраняете и запускаете ассемблер, который из файла с программой на языке ассемблера создает файл с перемещаемой программой на машинном языке. Наконец, компоновщик объединяет перемещаемую программу с другими ассемблированными подпрограммами и библиотечными программами и выдает выполнимую программу, которую вы (наконец-то!) запускаете. Для выполнения всех этих операций вам нужна сверх-программа, которая жонглировала бы всем этим хозяйством, отыскивая файлы на диске, загружая их в память и передавая управление соответствующим программам. Хотелось бы также избавиться от необходимости включения в каждую программу всех команд, требуемых для записи или чтения диска (включая обработку прерываний, загрузку регистров команд и состояний и проч.) или выполнения других операций по пересылке данных. Все это (и многое другое) входит в функции операционной системы, обширной программы, наблюдающей за загрузкой и запуском пользовательских программ (т. е. тех, которые вы пишите) и утилит (редактора, компилятора, ассемблера, компоновщика, отладчика и др.), а также управляющей вводом-выводом, системой прерываний и различными манипуляциями с файлами. Операционная система включает монитор для связи с пользователем (именно ему вы говорите, что надо вызвать редактор, или компилятор, или запустить программу) и набор «системных запросов», с помощью которых выполняемая программа может прочитать или записать строку текста на некотором устройстве, определить текущее время суток, передать управление другой программе, позволить нескольким «процессам» в многозадачной среде разделять между собой время ЦП или обмениваться данными, загружать программные «оверлеи» и т. д. Хорошая операционная система выполняет всю работу по управлению вводом-выводом, включая «спулинг» (буферизацию входных или выходных данных, позволяющую программе выполняться в то время, когда данные читаются или записываются на некотором устройстве). Выполняясь под управлением операционной системы, программа пользователя может не заботиться о прерываниях; прерывания обслуживаются системой и затрагивают ход программы только если программа сама хочет принять участие в обработке прерываний от конкретного устройства. Вершиной системного программирования является «разделение времени» (использование одного компьютера многими пользователями одновременно), когда диск служит в качестве «виртуальной памяти» для программ неограниченного размера. Примерами популярных микрокомпьютерных операционных систем являются MS-DOS (используемая на машинах IBM PC и их аналогах), OS/2 (предназначенная для машин PS/2, преемников IBM PC), UNIX (разработанная в Bell Labs и широко используемая на машинах VAX, а также на компьютерах с микропроцессором 68000), MacOS и VMS (операционная система машин VAX, предоставляемая компанией).